using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;

using Stonecode.Solar.ParticleEngine;
using Stonecode.Solar.ParticleEngine.Emitters;
using Stonecode.Solar.ParticleEngine.ParticleSystems;
using Stonecode.Solar.ParticleEngine.SettingsTemplate;
using System.Text;
using Stonecode.Solar.ParticleEngine.Collections;
using Stonecode.Solar.ParticleEngine.Data;
using System.Xml;

namespace Stonecode.Solar.ParticleEngineTest
{
    /// <summary>
    /// This is the main type for your game
    /// </summary>
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;

        EmitterCollection myEffect;
        

        Effect psystemEffect;

        Texture2D background;
        Rectangle screenRec;

        //Camera camera;
        Stonecode.Utils.Camera camera;
        KeyboardState lastState;
        int currentEmitter = 0;

        int fps = 0;
        float fpsTime = 0f;
        int fpsDraw = 0;
        SpriteFont font;
        const float startPos = 5f;
        float runTime = 0;
        float speed = 40f;
        float posY = 0;
        bool running;

        Dictionary<int, string> numbers = new Dictionary<int, string>();

        int gcShowIndex;
        int fpsShowIndex;
        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
            this.IsFixedTimeStep = false;
            graphics.SynchronizeWithVerticalRetrace = false;
            //fpsShow.Insert(0, "FPS:       ");
            //fpsShowIndex = 5;
            //gcShow.Insert(0, "GC Mem:        ");
            //gcShowIndex = 8;
            for (int i = 0; i < 10000; i++)
            {
                numbers.Add(i, i.ToString());
            }

        }

        /// <summary>
        /// Allows the game to perform any initialization it needs to before starting to run.
        /// This is where it can query for any required services and load any non-graphic
        /// related content.  Calling base.Initialize will enumerate through any components
        /// and initialize them as well.
        /// </summary>
        protected override void Initialize()
        {
            // TODO: Add your initialization logic here

            base.Initialize();
        }

        /// <summary>
        /// LoadContent will be called once per game and is the place to load
        /// all of your content.
        /// </summary>
        protected override void LoadContent()
        {
            // Create a new SpriteBatch, which can be used to draw textures.
            spriteBatch = new SpriteBatch(GraphicsDevice);

            screenRec = new Rectangle(0, 0, GraphicsDevice.Viewport.Width, GraphicsDevice.Viewport.Height);

            camera = new Stonecode.Utils.Camera(new Vector2(GraphicsDevice.Viewport.Width, GraphicsDevice.Viewport.Height), "Camera One");
            camera.AspectRatio = GraphicsDevice.Viewport.AspectRatio;
            camera.Position = new Vector3(0, 0, 100f);
            camera.Target = Vector3.Zero;
            camera.FieldOfView = 45f;
            camera.NearPlane = 1f;
            camera.FarPlane = 10000f;
            camera.UpdateMatricies();
            
            ////psystem.SetCamera(camera.ViewMatrix, camera.ProjectionMatrix);
            ////this.Components.Add(psystem);
            psystemEffect = Content.Load<Effect>("ParticleEffect");
            
            
            ParticleEffectImporter.CreateEmitterCollection(GraphicsDevice, psystemEffect, Content, Content.Load<EmitterCollectionInfo>("Smoke1"),
                camera.ViewMatrix, camera.ProjectionMatrix, out myEffect);

            //ParticleEffectImporter.ImportEmitterCollection(GraphicsDevice, psystemEffect, Content, "test", camera.ViewMatrix, camera.ProjectionMatrix, out myEffect);
            font = Content.Load<SpriteFont>("ConsoleFont");

            myEffect.Position = new Vector3(0, -20, 0);
            // TODO: use this.Content to load your game content here
        }

        /// <summary>
        /// UnloadContent will be called once per game and is the place to unload
        /// all content.
        /// </summary>
        protected override void UnloadContent()
        {
            // TODO: Unload any non ContentManager content here
        }

        /// <summary>
        /// Allows the game to run logic such as updating the world,
        /// checking for collisions, gathering input, and playing audio.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Update(GameTime gameTime)
        {
            // Allows the game to exit
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                this.Exit();
            float dt = (float)gameTime.ElapsedGameTime.TotalSeconds;
            

            KeyboardState kbState = Keyboard.GetState();
            if (kbState.IsKeyDown(Keys.Escape))
                this.Exit();

            if (kbState.IsKeyDown(Keys.Left))
                myEffect.Position += -Vector3.UnitX * dt * 10f;
            if (kbState.IsKeyDown(Keys.Right))
                myEffect.Position += Vector3.UnitX * dt * 10f;
            if (kbState.IsKeyDown(Keys.Up))
                myEffect.Position += Vector3.UnitY * dt * 10f;
            if (kbState.IsKeyDown(Keys.Down))
                myEffect.Position += -Vector3.UnitY * dt * 10f;

           
            //UpdateDisintegration(gameTime);
            myEffect.Update(dt);

            lastState = kbState;
            base.Update(gameTime);
        }

        void UpdateDisintegration(GameTime gameTime)
        {
            float dt = (float)gameTime.ElapsedGameTime.TotalSeconds;
            if (running)
            {
                posY -= (speed * dt);
                ((CircleEmitter)myEffect[0]).Position = Vector3.UnitY * posY;
                //((CircleEmitter)myEffect[1]).Position = Vector3.UnitY * posY;
                runTime += dt;
                if (runTime >= 1f)
                {
                    running = false;
                    myEffect[0].IsAlive = false;
                    //myEffect[1].IsAlive = false;
                    posY = startPos;
                    runTime = 0;
                }
            }
            else
            {
                myEffect[0].IsAlive = false;
                //myEffect[1].IsAlive = false;
                posY = startPos;
            }
            myEffect.Update(dt);
        }

        /// <summary>
        /// This is called when the game should draw itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);
            float dt = (float)gameTime.ElapsedGameTime.TotalSeconds;
            // TODO: Add your drawing code here
            spriteBatch.Begin();
            //spriteBatch.Draw(background, screenRec, Color.White);

            spriteBatch.DrawString(font, numbers[fpsDraw], Vector2.One * 20f, Color.Yellow);
            //spriteBatch.DrawString(font, numbers[(int)GC.GetTotalMemory(false) / 1024], new Vector2(10f, 30f), Color.Yellow);
            spriteBatch.End();

            myEffect.Draw(GraphicsDevice, dt);

            //base.Draw(gameTime);
            
            fps++;
            fpsTime += (float)gameTime.ElapsedGameTime.TotalSeconds;
            if (fpsTime >= 1f)
            {
                fpsDraw = (int)(fps / fpsTime);
                fpsTime = 0;
                fps = 0;
            }


            //AppendValueToSB(fpsShow, fpsDraw, fpsShowIndex);
            //AppendValueToSB(gcShow, (int)GC.GetTotalMemory(false) / 1024, gcShowIndex);
            
           
            
        }

        private void AppendValueToSB(StringBuilder sb, int value, int index)
        {
            int mindex = index;
            string s = value.ToString();
            for (int i = 0; i < s.Length; i++)
            {
                sb[mindex] = s[i];
                mindex++;
            }
            s = "";
        }
    }
}
